package com.seewo.dubbo.debugger.admin.service.impl;


import com.alibaba.dubbo.common.URL;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.seewo.dubbo.debugger.admin.common.Constants;
import com.seewo.dubbo.debugger.admin.entity.Interface;
import com.seewo.dubbo.debugger.admin.entity.Method;
import com.seewo.dubbo.debugger.admin.exception.DubboDebuggerException;
import com.seewo.dubbo.debugger.admin.mapper.InterfaceMapper;
import com.seewo.dubbo.debugger.admin.po.InterfaceServicePO;
import com.seewo.dubbo.debugger.admin.service.IInterfaceService;
import com.seewo.dubbo.debugger.admin.service.IMethodService;
import com.seewo.dubbo.debugger.admin.utils.EhcacheTemplate;
import com.seewo.dubbo.debugger.api.ApiDebuggerService;
import com.seewo.dubbo.debugger.api.model.ApiDef;
import com.seewo.dubbo.debugger.api.model.Document;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author chenliangliang
 * @since 2018-07-25
 */
@Slf4j
@Service
public class InterfaceServiceImpl extends ServiceImpl<InterfaceMapper, Interface> implements IInterfaceService {

    @Autowired
    private EhcacheTemplate ehcacheTemplate;

    @Autowired
    private ThreadPoolTaskExecutor executor;

    @Autowired
    private IMethodService methodService;

    @Override
    public InterfaceMapper getMapper() {
        return this.baseMapper;
    }


    @Override
    public Interface getMethods(Interface anterface) {
        final Integer serviceId = anterface.getCServiceId();
        final String interfaceName = anterface.getCName();
        InterfaceServicePO interfaceServicePo = baseMapper.selectInterfaceService(serviceId, interfaceName);
        if (interfaceServicePo == null) {
            throw new DubboDebuggerException("this interface-" + anterface + " not exist!");
        }
        //缓存数据15分钟
        return ehcacheTemplate.cacheable(Constants.CACHE_NAME_METHOD_LIST, serviceId + interfaceName, () -> getMethods0(anterface, interfaceServicePo));

    }

    private Interface getMethods0(Interface anterface, InterfaceServicePO interfaceServicePo) {
        final Integer interfaceId = interfaceServicePo.getInterfaceId();
        anterface.setCId(interfaceId);
        anterface.setCDesc(interfaceServicePo.getInterfaceDesc());
        //是否可以在线调试
        boolean canDebug = interfaceServicePo.getCanDebug() == 1;
        if (canDebug) {
            ApiDebuggerService debuggerService = methodService.getApiDebuggerService(anterface.getCServiceId(), interfaceServicePo.getAddress(), interfaceServicePo.getProtocol());
            Document doc = debuggerService.getDoc(anterface.getCName());
            List<ApiDef> apiList = doc.getApiList();
            List<Method> methods = new ArrayList<>();
            Set<String> methodNameSet = new HashSet<>();
            for (ApiDef apiDef : apiList) {
                String methodName = apiDef.getMethodName();
                Method method = new Method();
                method.setCInterfaceId(interfaceId);
                method.setCDesc(apiDef.getDescription());
                method.setCName(methodName);
                methodNameSet.add(methodName);
                methods.add(method);
            }

            List<Method> mList = new ArrayList<>();
            if (!methodNameSet.isEmpty()) {
                List<Method> methodList = methodService.selectList(new EntityWrapper<Method>()
                        .in("c_name", methodNameSet)
                        .eq("c_interface_id", interfaceId));

                Map<Method, Method> methodMap = new HashMap<>();
                methodList.forEach(m -> methodMap.put(m, m));

                List<Method> insertList = new ArrayList<>();
                for (Method method : methods) {
                    if (methodMap.containsKey(method)) {
                        mList.add(methodMap.get(method));
                    } else {
                        method.setCCreateTime(new Date());
                        method.setCUpdateTime(new Date());
                        mList.add(method);
                        insertList.add(method);
                    }
                }
                //异步更新t_method表
                executor.execute(() -> updateTableMethod(insertList));
            }
            anterface.setMethods(mList);
        } else {
            String url = interfaceServicePo.getUrl();
            URL ul = URL.valueOf(url);
            String methods = ul.getParameter("methods");
            String[] methodNames = methods.split(",");
            List<Method> methodList = new ArrayList<>();
            for (String methodName : methodNames) {
                Method method = new Method();
                method.setCName(methodName);
                method.setCInterfaceId(interfaceId);
                methodList.add(method);
            }
            anterface.setMethods(methodList);
        }
        return anterface;
    }

    @Override
    public void updateDesc(Interface anterface) {
        //异步更新缓存策略：先更新数据库，再删除缓存
        boolean res = updateById(anterface);
        if (res) {
            executor.execute(() -> {
                Interface anInterface = selectById(anterface.getCId());
                String key = anInterface.getCServiceId() + anInterface.getCName();
                ehcacheTemplate.cacheEvict(Constants.CACHE_NAME_METHOD_LIST, key);
            });
        } else {
            throw new DubboDebuggerException("更新描述失败");
        }
    }

    private void updateTableMethod(List<Method> insertList) {
        int size = insertList.size();
        if (size > 0) {
            int res = methodService.getMapper().batchInsert(insertList);
            if (res != size) {
                log.warn("批量插入method异常");
            }
        }
    }


}
